﻿namespace Centido.Core.Test
{
    using System;
    using System.Collections.Generic;
    using System.Data.Common;
    using System.Linq;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    /// <summary>
    /// Testing reference table column
    /// </summary>
    [TestClass]
    public class RefColumnTest : ColumnBaseTest<byte[]>
    {
        /// <summary>
        /// Column
        /// </summary>
        private RefColumn Column
        {
            get { return GenericColumn as RefColumn; }
        }

        /// <summary>
        /// Get column type
        /// </summary>
        /// <returns></returns>
        protected override ColumnType GetColumnType()
        {
            return ColumnType.Reference;
        }

        /// <summary>
        /// Get large value
        /// </summary>
        /// <returns></returns>
        protected override byte[] GetLargeValue()
        {
            var table = Domain.GetTable("yet_another_test_table");

            if (table == null)
            {
                table = Domain.AddTable("yet_another_test_table");
                table.GrantAll();
            }

            //Inserting a row in that table
            var rowId = table.InsertRow();

            var target = Column.GetTarget(table);

            if (target == null)
            {
                Column.AddTarget(table);
            }

            return rowId.ToByteArray();
        }

        /// <summary>
        /// Get small data
        /// </summary>
        /// <returns></returns>
        protected override byte[] GetSmallValue()
        {
            var table = Domain.GetTable("yet_another_test_table");

            if (table == null)
            {
                table = Domain.AddTable("yet_another_test_table");
                table.GrantAll();
            }

            //Inserting a row in that table
            var rowId = table.InsertRow();

            var target = Column.GetTarget(table);

            if (target == null)
            {
                Column.AddTarget(table);
            }

            return rowId.ToByteArray();
        }

        /// <summary>
        /// Convert db value
        /// </summary>
        /// <param name="dbValue">Db value</param>
        /// <returns></returns>
        protected override byte[] ConvertDbValue(object dbValue)
        {
            return DbValue.GetBinary(dbValue);
        }

        /// <summary>
        /// Adding reference targets
        /// </summary>
        [TestMethod]
        public void AddingReferenceTargets()
        {
            //Initially there must be no targets
            Assert.AreEqual(Column.Targets.Count(), 0);

            //Creating another table
            var anotherTable = Domain.AddTable("another_table");
            anotherTable.GrantAll();

            //Adding reference to another table
            var firstTarget = Column.AddTarget(anotherTable);

            Assert.IsNotNull(firstTarget);
            Assert.IsTrue(firstTarget.Exists());
            Assert.IsNotNull(Column.GetTarget(firstTarget.RefTable));
            Assert.AreEqual(firstTarget.Column.Name, Column.Name);
            Assert.AreEqual(firstTarget.RefTable.Name, anotherTable.Name);
            Assert.AreEqual(Column.Targets.Count(), 1);
            Assert.IsTrue(Column.Targets.Any(t => t.RefTable.Name == anotherTable.Name));

            //Adding reference to the same table
            var secondTarget = Column.AddTarget(Table);

            Assert.IsNotNull(secondTarget);
            Assert.IsTrue(secondTarget.Exists());
            Assert.IsNotNull(Column.GetTarget(firstTarget.RefTable));
            Assert.IsNotNull(Column.GetTarget(secondTarget.RefTable));
            Assert.AreEqual(secondTarget.Column.Name, Column.Name);
            Assert.AreEqual(secondTarget.RefTable.Name, Table.Name);
            Assert.AreEqual(Column.Targets.Count(), 2);
            Assert.IsTrue(Column.Targets.Any(t => t.RefTable.Name == anotherTable.Name));
            Assert.IsTrue(Column.Targets.Any(t => t.RefTable.Name == Table.Name));
        }

        /// <summary>
        /// Adding duplicate reference targets
        /// </summary>
        [TestMethod]
        public void AddingDuplicateReferenceTargets()
        {
            //Creating another table
            var anotherTable = Domain.AddTable("another_table");
            anotherTable.GrantAll();

            Column.AddTarget(anotherTable);

            Assert.AreEqual(Column.Targets.Count(), 1);

            try
            {
                Column.AddTarget(anotherTable);
            }
            catch (DbException e)
            {
                Assert.AreEqual(e.GetErrorCode(), DbErrorCode.AddingDuplicateRefTarget);
                return;
            }

            Assert.Fail();
        }

        /// <summary>
        /// Passing null when adding reference target
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void PassingNullWhenAddingReferenceTarget()
        {
            Column.AddTarget(null);
        }

        /// <summary>
        /// Removing reference targets
        /// </summary>
        [TestMethod]
        public void RemovingReferenceTargets()
        {
            //Creating another table
            var anotherTable = Domain.AddTable("another_table");
            anotherTable.GrantAll();

            //Adding two targets
            var firstTarget = Column.AddTarget(anotherTable);
            var secondTarget = Column.AddTarget(Table);

            Assert.AreEqual(Column.Targets.Count(), 2);

            //Removing the first target
            Column.DeleteTarget(firstTarget.RefTable);

            Assert.IsFalse(firstTarget.Exists());
            Assert.AreEqual(Column.Targets.Count(), 1);
            Assert.IsNull(Column.GetTarget(firstTarget.RefTable));
            Assert.IsFalse(Column.Targets.Any(t => t.RefTable.Name == firstTarget.RefTable.Name));
            Assert.IsNotNull(Column.GetTarget(secondTarget.RefTable));
            Assert.IsTrue(Column.Targets.Any(t => t.RefTable.Name == secondTarget.RefTable.Name));

            //Removing the second target
            secondTarget.Delete();

            Assert.AreEqual(Column.Targets.Count(), 0);
            Assert.IsFalse(secondTarget.Exists());
        }

        /// <summary>
        /// Removing reference target that doesn't exist
        /// </summary>
        [TestMethod]
        public void RemovingReferenceTargetThatDoesntExist()
        {
            //Adding reference target
            var target = Column.AddTarget(Table);

            Assert.AreEqual(Column.Targets.Count(), 1);

            //Removing reference target
            Column.DeleteTarget(target.RefTable);

            Assert.AreEqual(Column.Targets.Count(), 0);

            //Trying to remove that target again

            try
            {
                target.Delete();
            }
            catch (DbException e)
            {
                Assert.AreEqual(e.GetErrorCode(), DbErrorCode.DeletingNonexistentRefTarget);
                return;
            }

            Assert.Fail();
        }

        /// <summary>
        /// Setting property of reference target that was removed
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(DbOperationException))]
        public void SettingPropertyOfReferenceTargetThatWasRemoved()
        {
            //Creating reference target
            var target = Column.AddTarget(Table);

            target.HasCascadeDelete = true;

            Assert.AreEqual(target.HasCascadeDelete, true);

            //Removing that target
            target.Delete();

            //Trying to set a property
            target.HasCascadeDelete = false;
        }

        /// <summary>
        /// Passing null when removing reference target
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void PassingNullWhenRemovingReferenceTarget()
        {
            Column.DeleteTarget(referencedTable: null);
        }

        /// <summary>
        /// Inserting reference target value
        /// </summary>
        [TestMethod]
        public void InsertingReferenceTargetValue()
        {
            //Creating another table
            var anotherTable = Domain.AddTable("another_table");
            anotherTable.GrantAll();

            //Adding target
            Column.AddTarget(anotherTable);

            //Creating a row in another table
            var rowId = anotherTable.InsertRow();

            Assert.AreEqual(anotherTable.RowCount, 1);

            //Inserting reference value
            Table.InsertRow(GenericColumn.Value(rowId));

            Assert.AreEqual(Table.RowCount, 1);
        }

        /// <summary>
        /// Inserting self reference target value
        /// </summary>
        [TestMethod]
        public void InsertingSelfReferenceTargetValue()
        {
            //Adding target
            Column.AddTarget(Table);

            //Creating a row in a table
            var rowId = Table.InsertRow();

            Assert.AreEqual(Table.RowCount, 1);

            //Inserting reference value
            Table.InsertRow(GenericColumn.Value(rowId));

            Assert.AreEqual(Table.RowCount, 2);
        }

        /// <summary>
        /// Inserting two reference target values
        /// </summary>
        [TestMethod]
        public void InsertingTwoReferenceTargetValues()
        {
            //Creating another table
            var anotherTable = Domain.AddTable("another_table");
            anotherTable.GrantAll();

            //Adding first target
            Column.AddTarget(anotherTable);

            //Adding second target
            Column.AddTarget(Table);

            //Creating a row in another table
            var anotherRowId = anotherTable.InsertRow();

            Assert.AreEqual(anotherTable.RowCount, 1);

            //Creating a row in a table
            var rowId = Table.InsertRow();

            //Inserting first reference value
            Table.InsertRow(GenericColumn.Value(rowId));

            //Inserting second reference value
            Table.InsertRow(GenericColumn.Value(anotherRowId));

            Assert.AreEqual(Table.RowCount, 3);
        }

        /// <summary>
        /// Inserting a value when there are no targets
        /// </summary>
        [TestMethod]
        public void InsertingValueWhenThereAreNoTargets()
        {
            Assert.AreEqual(Column.Targets.Count(), 0);

            try
            {
                //Inserting reference value
                Table.InsertRow(GenericColumn.Value(Guid.NewGuid()));
            }
            catch (DbException e)
            {
                Assert.AreEqual(e.GetErrorCode(), DbErrorCode.ReferencedRowWasNotFound);
                Assert.AreEqual(Column.Targets.Count(), 0);
                return;
            }

            Assert.Fail();
        }

        /// <summary>
        /// Inserting null when there are no targets
        /// </summary>
        [TestMethod]
        public void InsertingNullWhenThereAreNoTargets()
        {
            Assert.AreEqual(Column.Targets.Count(), 0);

            //Inserting reference value
            Table.InsertRow(GenericColumn.Value(null));
        }

        /// <summary>
        /// Inserting non target value
        /// </summary>
        [TestMethod]
        public void InsertingNonTargetValue()
        {
            //Creating another table
            var anotherTable = Domain.AddTable("another_table");
            anotherTable.GrantAll();

            //Adding two targets
            Column.AddTarget(Table);
            Column.AddTarget(anotherTable);

            Assert.AreEqual(Column.Targets.Count(), 2);

            //Creating a row in another table
            anotherTable.InsertRow();

            Assert.AreEqual(anotherTable.RowCount, 1);

            //Creating a row in a table
            Table.InsertRow();

            try
            {
                //Inserting non reference value
                Table.InsertRow(GenericColumn.Value(Guid.NewGuid()));
            }
            catch (DbException e)
            {
                Assert.AreEqual(e.GetErrorCode(), DbErrorCode.ReferencedRowWasNotFound);
                Assert.AreEqual(Table.RowCount, 1); // Bug fix
                return;
            }

            Assert.Fail();
        }

        /// <summary>
        /// Inserting when a valid default value is set
        /// </summary>
        [TestMethod]
        public void InsertingWhenValidDefaultValueIsSet()
        {
            //Adding a target
            Column.AddTarget(Table);

            //Creating a row in a table
            var rowId = Table.InsertRow();

            Assert.AreEqual(Table.RowCount, 1);

            //Setting default value
            Column.DefaultValue = rowId;

            Assert.AreEqual(Column.DefaultValue, rowId);

            //Inserting a row
            var secondRowId = Table.InsertRow();

            Assert.AreEqual(Table.RowCount, 2);

            //Reading inserted value
            var inserted = GenericColumn.EmptyValue();

            Table.ReadRow(secondRowId, inserted);

            Assert.AreEqual(inserted.GetGuid(), rowId);
        }

        /// <summary>
        /// Inserting when a not valid default value is set
        /// </summary>
        [TestMethod]
        public void InsertingWhenNotValidDefaultValueIsSet()
        {
            //Setting default value
            Column.DefaultValue = Guid.NewGuid();

            try
            {
                //Inserting a row
                Table.InsertRow();
            }
            catch (DbException)
            {
                Assert.AreEqual(Table.RowCount, 0);
                return;
            }

            Assert.Fail();
        }

        /// <summary>
        /// Removing reference targets when values were inserted
        /// </summary>
        [TestMethod]
        public void RemovingReferenceTargetWhenValuesWereInserted()
        {
            //Creating another table
            var anotherTable = Domain.AddTable(StringProperty.RandomIdentifier());
            anotherTable.GrantAll();

            //Adding two targets
            Column.AddTarget(Table);
            Column.AddTarget(anotherTable);

            //Inserting row in another table
            var anotherTableRowId = anotherTable.InsertRow();

            Assert.AreEqual(anotherTable.RowCount, 1);

            //Inserting row in current table
            var currentTableRowId = Table.InsertRow();

            Assert.AreEqual(Table.RowCount, 1);

            //Inserting first reference value
            Table.InsertRow(GenericColumn.Value(currentTableRowId));

            //Inserting second reference value
            Table.InsertRow(GenericColumn.Value(anotherTableRowId));

            Assert.AreEqual(Table.RowCount, 3);

            //Removing the first target
            Column.DeleteTarget(Table);

            //Reading reference values
            var refValues = new List<Guid?>();

            var refValue = GenericColumn.EmptyValue();

            Table.ReadAllRows(() => refValues.Add(refValue.GetGuid()), refValue);

            Assert.AreEqual(refValues.Count, 3);
            Assert.AreEqual(refValues.Count(v => v == null), 2);
            Assert.AreEqual(refValues.Count(v => v == anotherTableRowId), 1);

            //Remving the second target
            Column.DeleteTarget(anotherTable);

            //Reading reference values
            refValues = new List<Guid?>();

            Table.ReadAllRows(() => refValues.Add(refValue.GetGuid()), refValue);

            Assert.AreEqual(refValues.Count, 3);
            Assert.AreEqual(refValues.Count(v => v == null), 3);
        }

        /// <summary>
        /// Removing reference target when a value was inserted and column is not null
        /// </summary>
        [TestMethod]
        public void RemovingReferenceTargetWhenValueWasInsertedAndIsNotNull()
        {
            //Creating another table
            var anotherTable = Domain.AddTable("another_table");
            anotherTable.GrantAll();

            //Adding a target
            Column.AddTarget(anotherTable);

            //Insert a row into another table
            var rowId = anotherTable.InsertRow();

            //Setting reference column to be not null
            Column.IsNotNull = true;

            //Inserting reference value
            Table.InsertRow(GenericColumn.Value(rowId));

            try
            {
                //Removing a target
                Column.DeleteTarget(anotherTable);
            }
            catch (DbException)
            {
                Assert.AreEqual(Column.Targets.Count, 1);
                return;
            }

            Assert.Fail();
        }

        /// <summary>
        /// Forming a cycle of two references
        /// </summary>
        [TestMethod]
        public void FormingCycleOfTwoReferences()
        {
            //Creating another table
            var anotherTable = Domain.AddTable("another_table");
            anotherTable.GrantAll();

            //Adding a reference to current table from another table
            var firstRef = (RefColumn)anotherTable.AddColumn("first_ref", ColumnType.Reference);

            Assert.IsNotNull(firstRef);

            var firstTarget = firstRef.AddTarget(Table);

            Assert.IsNotNull(firstTarget.RefTable);
            Assert.AreEqual(firstTarget.RefTable.Name, Table.Name);

            //Adding a reference to another table from current table
            var secondTarget = Column.AddTarget(anotherTable);

            Assert.IsNotNull(secondTarget.RefTable);
            Assert.AreEqual(secondTarget.RefTable.Name, anotherTable.Name);
        }

        /// <summary>
        /// Removing table that was referenced
        /// </summary>
        [TestMethod]
        public void RemovingTableThatWasReferenced()
        {
            //Creating another table
            var anotherTable = Domain.AddTable("another_table");
            anotherTable.GrantAll();

            //Referencing that table
            var target = Column.AddTarget(anotherTable);

            Assert.IsNotNull(target.RefTable);
            Assert.AreEqual(target.RefTable.Name, anotherTable.Name);

            try
            {
                //Trying to remove another table
                anotherTable.Delete();
            }
            catch (DbException)
            {
                Assert.IsTrue(anotherTable.Exists());
                return;
            }

            Assert.Fail();
        }

        /// <summary>
        /// Reading and writing cascade delete
        /// </summary>
        [TestMethod]
        public void ReadingAndWritingCascadeDelete()
        {
            //Creating a target
            var target = Column.AddTarget(Table);

            //Initially CascadeDelete must be false
            Assert.IsFalse(target.HasCascadeDelete);

            //Setting cascade delete to true
            target.HasCascadeDelete = true;

            Assert.IsTrue(target.HasCascadeDelete);

            //Setting cascade delete to false
            target.HasCascadeDelete = false;

            Assert.IsFalse(target.HasCascadeDelete);
        }

        /// <summary>
        /// Deleting referenced value with cascade delete
        /// </summary>
        [TestMethod]
        public void DeletingReferenceValueWithCascadeDelete()
        {
            //Creating another table
            var anotherTable = Domain.AddTable("another_table");
            anotherTable.GrantAll();

            //Adding first target
            var firstTarget = Column.AddTarget(anotherTable);

            //Adding second target
            var secondTarget = Column.AddTarget(Table);

            //Setting CascadeDelete for targets
            firstTarget.HasCascadeDelete = true;
            secondTarget.HasCascadeDelete = true;

            //Inserting a row in another table
            var anotherTableRowId = anotherTable.InsertRow();

            Assert.AreEqual(anotherTable.RowCount, 1);

            //Inserting reference value to another table
            var currentTableRowId = Table.InsertRow(GenericColumn.Value(anotherTableRowId));

            Assert.AreEqual(Table.RowCount, 1);

            //Inserting self-reference value
            Table.InsertRow(GenericColumn.Value(currentTableRowId));

            //Deleting referenced value in another table
            anotherTable.DeleteRow(anotherTableRowId);

            Assert.AreEqual(anotherTable.RowCount, 0);
            Assert.AreEqual(Table.RowCount, 0);
        }

        /// <summary>
        /// Deleting referenced value without cascade delete
        /// </summary>
        [TestMethod]
        public void DeletingReferenceValueWithoutCascadeDelete()
        {
            // Otherwise a delete operation is always cascade
            Table.Domain.HasRecycleBin = true;

            //Creating another table
            var anotherTable = Domain.AddTable("another_table");
            anotherTable.GrantAll();

            //Setting reference to another table
            Column.AddTarget(anotherTable);

            //Inserting a row in another table
            var anotherTableRowId = anotherTable.InsertRow();

            Assert.AreEqual(anotherTable.RowCount, 1);

            //Inserting reference value
            Table.InsertRow(GenericColumn.Value(anotherTableRowId));

            Assert.AreEqual(Table.RowCount, 1);

            try
            {
                //Deleting referenced value
                anotherTable.DeleteRow(anotherTableRowId);
            }
            catch (DbException e)
            {
                Assert.AreEqual(e.GetErrorCode(), DbErrorCode.DeletingWhenThereAreRefsWithFalseCascadeDelete);
                return;
            }

            Assert.Fail();
        }

        /// <summary>
        /// Deleting reference value first and then a master value without cascade delete
        /// </summary>
        [TestMethod]
        public void DeletingReferenceValueFirstWithoutCascadeDelete()
        {
            //Creating another table
            var anotherTable = Domain.AddTable("another_table");
            anotherTable.GrantAll();

            //Setting reference to another table
            Column.AddTarget(anotherTable);

            //Inserting a row in another table
            var anotherTableRowId = anotherTable.InsertRow();

            Assert.AreEqual(anotherTable.RowCount, 1);

            //Inserting reference value
            var rowId = Table.InsertRow(GenericColumn.Value(anotherTableRowId));

            Assert.AreEqual(Table.RowCount, 1);

            //Deleting reference value
            Table.DeleteRow(rowId);

            Assert.AreEqual(Table.RowCount, 0);

            //And then deleting the master value
            anotherTable.DeleteRow(anotherTableRowId);

            Assert.AreEqual(anotherTable.RowCount, 0);
        }

        /// <summary>
        /// Deleting a chain of reference values with cascade delete
        /// </summary>
        [TestMethod]
        public void DeletingChainOfReferenceValuesWithCascadeDelete()
        {
            //Creating the second table
            var secondTable = Domain.AddTable("second_table");
            secondTable.GrantAll();

            //Setting reference to second table
            Column.AddTarget(secondTable).HasCascadeDelete = true;

            //Adding ref column to second table
            var secondTableRefColumn = (RefColumn)secondTable.AddColumn("ref_column", ColumnType.Reference);

            //Creating the third table
            var thirdTable = Domain.AddTable("third_table");
            thirdTable.GrantAll();

            //Setting reference to third table
            secondTableRefColumn.AddTarget(thirdTable).HasCascadeDelete = true;

            //Inserting a row in the third table
            var thirdTableRowId = thirdTable.InsertRow();

            Assert.AreEqual(thirdTable.RowCount, 1);

            //Second table row id
            Guid.NewGuid();

            //Inserting a row in the second table
            var secondTableRowId = secondTable.InsertRow(secondTableRefColumn.Value(thirdTableRowId));

            Assert.AreEqual(secondTable.RowCount, 1);

            //Inserting reference value
            Table.InsertRow(GenericColumn.Value(secondTableRowId));

            Assert.AreEqual(Table.RowCount, 1);

            //Deleting value from the third table
            thirdTable.DeleteRow(thirdTableRowId);

            Assert.AreEqual(thirdTable.RowCount, 0);
            Assert.AreEqual(secondTable.RowCount, 0);
            Assert.AreEqual(Table.RowCount, 0);
        }

        /// <summary>
        /// Deleting a chain of reference values without one cascade delete
        /// </summary>
        [TestMethod]
        public void DeletingChainOfReferenceValuesWithoutOneCascadeDelete()
        {
            Domain.HasRecycleBin = true;

            //Creating the second table
            var secondTable = Domain.AddTable("second_table");
            secondTable.GrantAll();

            //Setting reference to second table
            //No cascade delete!
            Column.AddTarget(secondTable);

            //Adding ref column to second table
            var secondTableRefColumn = (RefColumn)secondTable.AddColumn("ref_column", ColumnType.Reference);

            //Creating the third table
            var thirdTable = Domain.AddTable("third_table");
            thirdTable.GrantAll();

            //Setting reference to third table
            secondTableRefColumn.AddTarget(thirdTable).HasCascadeDelete = true;

            //Inserting a row in the third table
            var thirdTableRowId = thirdTable.InsertRow();

            Assert.AreEqual(thirdTable.RowCount, 1);

            //Inserting a row in the second table
            var secondTableRowId = secondTable.InsertRow(secondTableRefColumn.Value(thirdTableRowId));

            Assert.AreEqual(secondTable.RowCount, 1);

            //Inserting reference value
            Table.InsertRow(GenericColumn.Value(secondTableRowId));

            Assert.AreEqual(Table.RowCount, 1);

            try
            {
                //Deleting value from the third table
                thirdTable.DeleteRow(thirdTableRowId);
            }
            catch (DbException e)
            {
                Assert.AreEqual(e.GetErrorCode(), DbErrorCode.DeletingWhenThereAreRefsWithFalseCascadeDelete);
                Assert.AreEqual(Table.RowCount, 1);
                Assert.AreEqual(secondTable.RowCount, 1);
                Assert.AreEqual(thirdTable.RowCount, 1);
                return;
            }

            Assert.Fail();
        }

        /// <summary>
        /// Deleting a row with tow links on the same table.
        /// </summary>
        [TestMethod]
        public void DeletingRowWithTwoLinksOnTheSameTable()
        {
            //Creating another table
            var anotherTable = Domain.AddTable(StringProperty.RandomIdentifier());
            anotherTable.GrantAll();

            //Creating the first reference column
            Column.AddTarget(anotherTable).HasCascadeDelete = true;

            //Creating the second reference column
            var anotherRefColumn =
                Table.AddColumn(StringProperty.RandomIdentifier(), ColumnType.Reference) as RefColumn;

            if (anotherRefColumn == null) return;

            anotherRefColumn.AddTarget(anotherTable).HasCascadeDelete = true;

            //Adding rows in another table
            var anotherTableRowId = anotherTable.InsertRow();

            //Adding a row with two links
            Table.InsertRow(GenericColumn.Value(anotherTableRowId), anotherRefColumn.Value(anotherTableRowId));

            Assert.AreEqual(Table.RowCount, 1);
            Assert.AreEqual(anotherTable.RowCount, 1);

            //Deleting the row with two links
            anotherTable.DeleteRow(anotherTableRowId);

            Assert.AreEqual(Table.RowCount, 0);
            Assert.AreEqual(anotherTable.RowCount, 0);
        }

        /// <summary>
        /// Inserting a row after deleting a ref column
        /// </summary>
        [TestMethod]
        public void InsertingRowAfterDeletingRefColumn()
        {
            Column.Delete();

            Table.InsertRow();

            Assert.AreEqual(Table.RowCount, 1);
        }

        /// <summary>
        /// Inserting a row after renaming a ref column
        /// </summary>
        [TestMethod]
        public void InsertingRowAfterRenamingRefColumn()
        {
            //Another table
            var anotherTable = Domain.AddTable(StringProperty.RandomIdentifier());

            Column.AddTarget(anotherTable);

            //Renaming ref column
            Column.Name = StringProperty.RandomIdentifier();

            //Inserting a ref row
            anotherTable.GrantAll();

            var id = anotherTable.InsertRow();

            Table.InsertRow(Column.Value(id));

            Assert.AreEqual(Table.RowCount, 1);
        }


        /// <summary>
        /// Deleting on cascade with no delete permission
        /// </summary>
        [TestMethod]
        public void DeletingOnCascadeWithNoPermission()
        {
            //Creating another table
            var anotherTable = Domain.AddTable(StringProperty.RandomIdentifier());
            anotherTable.GrantAll();

            var refColumn = Table.AddColumn(StringProperty.RandomIdentifier(), ColumnType.Reference)
                            as RefColumn;

            if (refColumn == null) return;

            refColumn.AddTarget(anotherTable).HasCascadeDelete = true;

            //Inserting rows
            var id = anotherTable.InsertRow();

            Table.InsertRow(refColumn.Value(id));

            //Creating a user
            var userPassword = StringProperty.RandomPassword();
            var user = Domain.AddUser(StringProperty.RandomIdentifier(), userPassword);

            var userDomain = Domain.Logon(user.Name, userPassword);

            //Granting permissions ONLY on another table
            anotherTable.GrantAll(user);

            //Deleting the row in another table
            userDomain.GetTable(anotherTable.Name).DeleteRow(id);

            Assert.AreEqual(Table.RowCount, 0);
            Assert.AreEqual(anotherTable.RowCount, 0);
        }


        /// <summary>
        /// Checking the ref value with no permission
        /// </summary>
        [TestMethod]
        public void CheckingRefValueWithNoPermission()
        {
            Domain.HasRecycleBin = true;

            //Creating a ref on another table
            var anotherTable = Domain.AddTable(StringProperty.RandomIdentifier());
            anotherTable.GrantAll();

            Column.AddTarget(anotherTable);

            var id = anotherTable.InsertRow();

            //Soft deleting this row
            anotherTable.DeleteRow(id);

            //Creating a user
            var userPassword = StringProperty.RandomPassword();
            var user = Domain.AddUser(StringProperty.RandomIdentifier(), userPassword);

            //Granting permissions ONLY on the first table
            Table.GrantAll(user);

            //Inserting a row from the user
            var userDomain = Domain.Logon(user.Name, userPassword);

            userDomain.GetTable(Table.Name).InsertRow(GenericColumn.Value(id));

            Assert.AreEqual(Table.RowCount, 1);
            Assert.AreEqual(anotherTable.RowCount, 0);
        }


        /// <summary>
        ///   Reading and writing reference checking property.
        /// </summary>
        [TestMethod]
        public void ReadingAndWritingReferenceChecking()
        {
            Assert.IsTrue(Column.HasReferenceChecking);

            Column.HasReferenceChecking = false;
            Column.HasReferenceChecking = false;

            Assert.IsFalse(Column.HasReferenceChecking);

            Column.HasReferenceChecking = true;
            Column.HasReferenceChecking = true;

            Assert.IsTrue(Column.HasReferenceChecking);
        }


        /// <summary>
        ///   Inserting an invalid value when reference checking is disabled.
        /// </summary>
        [TestMethod]
        public void InsertingInvalidValueWhenCheckingIsDisabled()
        {
            Assert.AreEqual(Table.RowCount, 0);

            Column.HasReferenceChecking = false;

            Table.InsertRow(Column.Value(Guid.NewGuid()));

            Column.HasReferenceChecking = true;

            Assert.AreEqual(Table.RowCount, 1);
        }
    }
}